﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "PickSuperInstanceBeforeSubInstanceEventHandler.h"

#include "IDocument.h"
#include "IPick.h"
#include "IPickResult.h"
#include "IPickEventArgs.h"
#include "IGraphicsNodeReference.h"
#include "IInstance.h"
#include <stack>

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;


void PickSuperInstanceBeforeSubInstanceEventHandler::Process(IDocument* pDoc, IPickEventArgs * pArgs, const Vector3d & pos) const
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc && pArgs, L"ParamInputted is invalid!",L"GDMPLab",L"2024-03-30");

    OwnerPtr<IPickResult> pickResult = pArgs->GetPickCandidates().Clone();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pickResult, L"pickResult is nullptr!",L"GDMPLab",L"2024-03-30");
    std::vector<OwnerPtr<IPick>>& allPicks = pickResult->GetAllPicks();
    allPicks.clear();

    OwnerPtr<IPickResult> resultInput = pArgs->GetPickCandidates().Clone();
    DBG_WARN_AND_RETURN_VOID_UNLESS(resultInput, L"resultInput is nullptr!",L"GDMPLab",L"2024-03-30");

    std::vector<OwnerPtr<IPick>>& picksInputted = resultInput->GetAllPicks();
    for (auto& opPick : picksInputted)
    {
        DBG_WARN_AND_CONTINUE_UNLESS(opPick, L"拾取结果为空",L"GDMPLab",L"2024-03-30");
        const gcmp::IGraphicsNodeReference* pGNodeRef = opPick->GetFront();
        if (!pGNodeRef)
            continue;

        const IElement* pElement = pDoc->GetElement(pGNodeRef->GetElementId());
        if (!pElement)
            continue;

        const IInstance* pInstance = quick_cast<IInstance>(pElement);
        if (!pInstance)
        {
            pickResult->AddPick(TransferOwnership(opPick));
            continue;
        }

        // 嵌套族相关处理逻辑
        if (ElementId::InvalidID != pInstance->GetSuperInstanceId() || !pInstance->GetSubInstanceIds().empty())
        {
            ElementId currentId = pInstance->GetSuperInstanceId();
            std::vector<ElementId> superLineIds;
            superLineIds.emplace_back(pGNodeRef->GetElementId());
            while (ElementId::InvalidID != currentId)
            {
                superLineIds.emplace_back(currentId);

                pInstance = quick_cast<IInstance>(pDoc->GetElement(currentId));
                DBG_WARN_AND_BREAK_UNLESS(pInstance, L"pInstance is nullptr!",L"GDMPLab",L"2024-03-30");
                currentId = pInstance->GetSuperInstanceId();
            }

            std::stack<OwnerPtr<IPick>> superLinePicks;

            OwnerPtr<GraphicsNodeAndTransform> intersectGraphicsNode = pGNodeRef->GetIntersectGraphicsNode();
            DBG_WARN_AND_CONTINUE_UNLESS(intersectGraphicsNode, L"intersectGraphicsNode is nullptr!",L"GDMPLab",L"2024-03-30");
            const Vector3d& untransformedIntersectPoint = pGNodeRef->GetUntransformedIntersectPoint();
            const IGraphicsNode* intersectGNode = (intersectGraphicsNode->m_wpGraphicsNode).Get();
            Matrix4d* transform = (intersectGraphicsNode->m_opTransfrom).get();

            for (auto itor = superLineIds.begin(); itor != superLineIds.end(); ++itor)
            {
                const IInstance* pTempInstance = quick_cast<IInstance>(pDoc->GetElement(*itor));
                DBG_WARN_AND_BREAK_UNLESS(pTempInstance, L"pTempInstance is nullptr!",L"GDMPLab",L"2024-03-30");
                std::vector<ElementId> subInstanceIds = pTempInstance->GetAllSubInstanceIds();
                subInstanceIds.emplace_back(*itor);

                OwnerPtr<IPick> tmpPick = IPick::Create();
                DBG_WARN_AND_BREAK_UNLESS(tmpPick, L"tmpPick is nullptr!",L"GDMPLab",L"2024-03-30");
                for (auto id : subInstanceIds)
                {
                    OwnerPtr<IGraphicsNodeReference> nodeRef = IGraphicsNodeReference::CreateGraphicsElementShapeReference(id);
                    DBG_WARN_AND_BREAK_UNLESS(nodeRef, L"nodeRef is nullptr!",L"GDMPLab",L"2024-03-30");
                    nodeRef->SetIntersectData(untransformedIntersectPoint, intersectGNode, transform);
                    tmpPick->AddGraphicsNodeReference(*nodeRef);
                }

                if (!tmpPick->GetAllGraphicsNodeReferences().empty())
                    superLinePicks.push(TransferOwnership(tmpPick));
            }

            while (!superLinePicks.empty())
            {
                pickResult->AddPick(TransferOwnership(superLinePicks.top()));
                superLinePicks.pop();
            }

            continue;
        }

        pickResult->AddPick(TransferOwnership(opPick));
    }

    pArgs->SetPickCandidates(*pickResult);
}
